package cn.xawl.interview.thread;


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author lh
 * @date 2020/08/26 20:57:22
 * 阻塞队列版生产者消费者模型：volatile/CAS/AtomicInteger/BlockingQueue/线程交互/原子引用
 **/
public class ProductConsumerDemo02 {

    public static void main(String[] args) {
        Cake cake = new Cake(new ArrayBlockingQueue<>(5));
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "\t开始生产");
                cake.product();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "Product").start();
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "\t开始消费");
                cake.consumer();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "Consumer").start();

        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("5秒钟过后，老板通知停止生产消费");
        cake.stop();
        System.out.println(Thread.currentThread().getName() + "叫停");

    }


}

class Cake {
    //控制生产和消费。默认为true
    private volatile boolean FLAG = true;
    private final AtomicInteger atomicInteger = new AtomicInteger();
    private final BlockingQueue<Integer> blockingQueue;

    public Cake(BlockingQueue<Integer> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    //*注意：while循环中，将变量尽量写在循环体外，否则每次循环都会创建变量。
    public void product() throws InterruptedException {
        int data ;
        boolean isOffer;
        while (FLAG) {
            //向队列中插入一个数据，如果不能插入等待两秒还未能插入后返回false
            data = atomicInteger.incrementAndGet();
            isOffer = blockingQueue.offer(data, 2L, TimeUnit.SECONDS);
            if (isOffer) {
                System.out.println(Thread.currentThread().getName() + "\t生产第" + data + "个蛋糕成功");
            } else {
                System.out.println(Thread.currentThread().getName() + "\t生产第" + data + "个蛋糕失败");
            }
            TimeUnit.SECONDS.sleep(1);
        }
        System.out.println("老板叫停了生产动作");
    }

    public void consumer() throws InterruptedException {
        Integer result;
        while (FLAG) {
            result = blockingQueue.poll(2L, TimeUnit.SECONDS);
            if (result == null) {
                FLAG = false;
                System.out.println("超过2秒没有取出蛋糕，消费过程结束");
                return;
            }
            System.out.println(Thread.currentThread().getName() + "\r消费了第" + result + "个蛋糕");
        }
    }

    public void stop() {
        this.FLAG = false;
    }


}
